module PluginAWeek #:nodoc:
  module LoadedPlugins
    module Extensions #:nodoc:
      # Keeps track of all the plugins that Rails loaded during initialization
      module Initializer
        def self.included(base) #:nodoc:
          base.class_eval do
            # HACK: Commented out the next line because load_plugin was removed from edge
            # alias_method_chain :load_plugin, :loaded_plugins
            alias_method_chain :after_initialize, :loaded_plugins
          end
        end
        
        def self.extended(initializer) #:nodoc:
          # Get all of the paths we missed before this plugin was loaded.  This
          # is only necessary for plugins that need +Rails.plugins+ during
          # initialization.
          # 
          # HACK: Commented out the next line because add_loaded_plugins was removed from edge
          # initializer.add_loaded_plugins
        end
        
        def load_plugin
        end
        
        # Loads the plugin from the specified directory, tracking all successfully
        # loaded plugins in +Rails.plugins+
        def load_plugin_with_loaded_plugins(directory)
          plugin = Plugin.new(directory)
          return false if loaded_plugins.include?(plugin.name)
          
          # Be careful to place the plugin in the correct order in case a plugin
          # has required another plugin
          if @loaded_plugin_index
            Rails.plugins.insert(@loaded_plugin_index, plugin)
          else
            Rails.plugins << plugin
            @loaded_plugin_index = Rails.plugins.size - 1
          end
          
          # Plugin is about to be loaded
          plugin.before_load
          
          load_plugin_without_loaded_plugins(directory)
          
          # Plugin has been loaded
          plugin.after_load
          
          # We no longer need to track the current index in LOADED_PLUGINS if
          # we're the last one
          @loaded_plugin_index = nil if Rails.plugins.last == plugin
          
          true
        end
        
        # Freezes the list of loaded plugins and invokes the +after_initialize+
        # callback for each plugin
        def after_initialize_with_loaded_plugins #:nodoc:
          add_loaded_plugins
          Rails.plugins.freeze
          Rails.plugins.each {|plugin| plugin.after_initialize}
          
          after_initialize_without_loaded_plugins
        end
        
        # Adds all of the loaded plugins that were missed to +Rails.plugins+
        def add_loaded_plugins
          loaded_plugins.reverse.each do |name|
            if !Rails.plugins[name] && path = find_plugin_path(name)
              Rails.plugins.insert(0, Plugin.new(path))
            end
          end
        end
        
        private
        # Finds the path of the specified plugin
        def find_plugin_path(name)
          find_plugins(configuration.plugin_paths).find {|path| Plugin.name_for(path) == name}
        end
        
        # HACK: Edge removed this method (and the two that follow). I added them back.
        def find_plugins(*base_paths)
          base_paths.flatten.inject([]) do |plugins, base_path|
            Dir.glob(File.join(base_path, '*')).each do |path|
              if plugin_path?(path)
                plugins << path if plugin_enabled?(path)
              elsif File.directory?(path)
                plugins += find_plugins(path)
              end
            end
            plugins
          end
        end
        
        def plugin_path?(path)
          File.directory?(path) and (File.directory?(File.join(path, 'lib')) or File.file?(File.join(path, 'init.rb')))
        end
  
        def plugin_enabled?(path)
          configuration.plugins.nil? || configuration.plugins.include?(File.basename(path))
        end
        
      end
    end
  end
end

Rails::Initializer.class_eval do
  include PluginAWeek::LoadedPlugins::Extensions::Initializer
end
